#include "sqlite3helper.h"

#include "cocos2d.h"
#include "sqlite3.h"

using namespace cocos2d;

static bool _initialized = false;
static sqlite3 *_db;
static sqlite3_stmt *_stmt_select;
static sqlite3_stmt *_stmt_remove;
static sqlite3_stmt *_stmt_update;


void SQLite3Helper::createDataTable() {
	const char *sql_createtable = "CREATE TABLE IF NOT EXISTS data(key TEXT PRIMARY KEY,value TEXT);";
	sqlite3_stmt *stmt;
	int ok = sqlite3_prepare_v2(_db, sql_createtable, -1, &stmt, NULL);
	ok |= sqlite3_step(stmt);
	ok |= sqlite3_finalize(stmt);

	if (ok != SQLITE_OK && ok != SQLITE_DONE)
		printf("Error in CREATE TABLE\n");
}

bool SQLite3Helper::init() {
	int ret = SQLITE_OK;

	if (_initialized) {
		return ret == SQLITE_OK || ret == SQLITE_DONE;
	}

	std::string fullpath = CCFileUtils::sharedFileUtils()->getWritablePath() + "data.db3";
	int ok = sqlite3_open(fullpath.c_str(), &_db);
	if (ok == SQLITE_OK || ok == SQLITE_DONE) {
		createDataTable();
	} else {
		printf("Error in open db\n");
	}


	// SELECT
	const char *sql_select = "SELECT value FROM data WHERE key=?;";
	ret |= sqlite3_prepare_v2(_db, sql_select, -1, &_stmt_select, NULL);

	// REPLACE
	const char *sql_update = "REPLACE INTO data (key, value) VALUES (?,?);";
	ret |= sqlite3_prepare_v2(_db, sql_update, -1, &_stmt_update, NULL);

	// DELETE
	const char *sql_remove = "DELETE FROM data WHERE key=?;";
	ret |= sqlite3_prepare_v2(_db, sql_remove, -1, &_stmt_remove, NULL);

	if (ret != SQLITE_OK ) {
		printf("Error initializing DB\n");
		// report error
	}

	_initialized = true;

	return ret == SQLITE_OK || ret == SQLITE_DONE;;

}

void SQLite3Helper::release() {
	if (_initialized) {
		sqlite3_finalize(_stmt_select);
		sqlite3_finalize(_stmt_remove);
		sqlite3_finalize(_stmt_update);

		sqlite3_close(_db);

		_initialized = false;
	}
}

const char *SQLite3Helper::get(const char *key) {
	assert( _initialized );

	int ok = sqlite3_reset(_stmt_select);

	ok |= sqlite3_bind_text(_stmt_select, 1, key, -1, SQLITE_TRANSIENT);
	ok |= sqlite3_step(_stmt_select);
	const unsigned char *ret = sqlite3_column_text(_stmt_select, 0);

	if (ok != SQLITE_OK && ok != SQLITE_DONE && ok != SQLITE_ROW)
		printf("Error in SQLite3Helper.get()\n");

	return (const char *) ret;
}

void SQLite3Helper::set(const char *key, const char *value) {
	assert( _initialized );

	int ok = sqlite3_bind_text(_stmt_update, 1, key, -1, SQLITE_TRANSIENT);
	ok |= sqlite3_bind_text(_stmt_update, 2, value, -1, SQLITE_TRANSIENT);

	ok |= sqlite3_step(_stmt_update);

	ok |= sqlite3_reset(_stmt_update);

	if (ok != SQLITE_OK && ok != SQLITE_DONE)
		printf("Error in SQLite3Helper.set()\n");
}

const char *SQLite3Helper::getBlob(const char *key, int& n) {
	assert( _initialized );

	int ok = sqlite3_reset(_stmt_select);

	ok |= sqlite3_bind_text(_stmt_select, 1, key, -1, SQLITE_TRANSIENT);
	ok |= sqlite3_step(_stmt_select);
	const void *ret = sqlite3_column_blob(_stmt_select, 0);

	n = sqlite3_column_bytes(_stmt_select, 0);

	if (ok != SQLITE_OK && ok != SQLITE_DONE && ok != SQLITE_ROW)
		printf("Error in SQLite3Helper.getBlob()\n");

	return (const char *) ret;
}

void SQLite3Helper::setBlob(const char *key, const char *value, int n) {
	assert( _initialized );

	int ok = sqlite3_bind_text(_stmt_update, 1, key, -1, SQLITE_TRANSIENT);
	ok |= sqlite3_bind_blob(_stmt_update, 2, value, n, SQLITE_TRANSIENT);

	ok |= sqlite3_step(_stmt_update);

	ok |= sqlite3_reset(_stmt_update);

	if (ok != SQLITE_OK && ok != SQLITE_DONE)
		printf("Error in SQLite3Helper.setBlob()\n");
}

void SQLite3Helper::remove(const char *key) {
	assert( _initialized );

	int ok = sqlite3_bind_text(_stmt_remove, 1, key, -1, SQLITE_TRANSIENT);

	ok |= sqlite3_step(_stmt_remove);

	ok |= sqlite3_reset(_stmt_remove);

	if (ok != SQLITE_OK && ok != SQLITE_DONE)
		printf("Error in localStorage.removeItem()\n");
}

void SQLite3Helper::setInt(const char *key, int value) {
	assert( _initialized );

	int ok = sqlite3_bind_text(_stmt_update, 1, key, -1, SQLITE_TRANSIENT);
	ok |= sqlite3_bind_int(_stmt_update, 2, value);

	ok |= sqlite3_step(_stmt_update);

	ok |= sqlite3_reset(_stmt_update);

	if (ok != SQLITE_OK && ok != SQLITE_DONE)
		printf("Error in SQLite3Helper.set()\n");
}

int SQLite3Helper::getInt(const char *key) {
	assert( _initialized );

	int ok = sqlite3_reset(_stmt_select);

	ok |= sqlite3_bind_text(_stmt_select, 1, key, -1, SQLITE_TRANSIENT);
	ok |= sqlite3_step(_stmt_select);
	int ret = sqlite3_column_int(_stmt_select, 0);

	if (ok != SQLITE_OK && ok != SQLITE_DONE && ok != SQLITE_ROW)
		printf("Error in SQLite3Helper.getBlob()\n");

	return ret;
}
